package intf.impl;

import intf.ICommonItem;
import intf.ILine;
import intf.IPoint;
import algo.Geom;

/**
 * Created by IntelliJ IDEA. User: sigolaev_va Date: 05.02.2013 Time: 17:22:06
 * Point implementation
 */
public class PointImpl implements IPoint
{

	private double m_x, m_y;
	private byte m_type;

	protected double m_cost;
	protected ILine m_hostLine;
	protected String m_name;

	public PointImpl()
	{
		this(Geom.TYPE_WELL_ITEM);
	}

	public PointImpl( byte type)
	{
		switch (type)
		{
		case Geom.TYPE_WELL_ITEM:
		case Geom.TYPE_STEINER_ITEM:
		case Geom.TYPE_COLLECT_ITEM:
			m_type = type;
			break;
		default:
			throw new IllegalArgumentException("Type expected to be from "
			        + Geom.TYPE_WELL_ITEM + " to " + Geom.TYPE_STEINER_ITEM
			        + " inclusively, detected " + type);
		}
	}

	public IPoint copy()
	{
		PointImpl point = new PointImpl(m_type, m_x, m_y);
		point.m_cost = m_cost;
		point.m_hostLine = m_hostLine;
		return point;
	}

	public PointImpl( byte type, double x, double y)
	{
		this(type);
		m_x = x;
		m_y = y;
	}

	public PointImpl( double x, double y)
	{
		this();
		m_x = x;
		m_y = y;
	}

	public double X()
	{
		return m_x;
	}

	public double Y()
	{
		return m_y;
	}

	public void setXY( double x, double y )
	{
		m_x = x;
		m_y = y;
	}

	public double distanceTo( ICommonItem item )
	{
		return item.distanceFrom(this);
	}

	public double setDCost( double val )
	{
		return m_cost = val;
	}

	public ILine host()
	{
		return m_hostLine;
	}

	public byte type()
	{
		return m_type;
	}

	public boolean isLine()
	{
		return false;
	}

	public boolean isPoint()
	{
		return true;
	}

	public double distanceFrom( ICommonItem item )
	{
		if ( item.isPoint() )
			return Geom.distance(((IPoint) item).X(), ((IPoint) item).Y(),
			        this.m_x, this.m_y);
		// not point, so find the nearest point
		MyPoint mp = new MyPoint();
		double perp = Geom.perpendicular(mp, m_x, m_y, ((ILine) item)
		        .startPoint().X(), ((ILine) item).startPoint().Y(),
		        ((ILine) item).endPoint().X(), ((ILine) item).endPoint().Y());
		if ( perp <= 0.0 )
			return Geom.distance(m_x, m_y, ((ILine) item).startPoint().X(),
			        ((ILine) item).startPoint().Y());
		if ( perp >= 1.0 )
			return Geom.distance(m_x, m_y, ((ILine) item).endPoint().X(),
			        ((ILine) item).endPoint().Y());
		return Geom.distance(mp.m_x, mp.m_y, m_x, m_y);
	}

	public ICommonItem buildConnectItem( IPoint pnt )
	{
		// connect two points so that start one is our point and end one is
		// designated one
		ILine line = new LineImpl(this, pnt, pnt.type());
		// set cost value for a new point
		return line;
	}

	public String name()
	{
		return m_name;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return String.format("[x=%s, y=%s]", m_x, m_y);
	}

	/**
	 * Simplest point to use as temp storage
	 */
	protected static class MyPoint implements IPoint
	{

		double m_x, m_y;

		/**
		 * Deklivery cost (in meters or any other length items)
		 */
		private double m_cost;

		public double X()
		{
			return m_x;
		}

		public double Y()
		{
			return m_y;
		}

		public void setXY( double x, double y )
		{
			m_x = x;
			m_y = y;
		}

		public double distanceTo( ICommonItem item )
		{
			return 0;
		}

		public double setDCost( double val )
		{
			return m_cost;
		}

		public ILine host()
		{
			return null;
		}

		public IPoint copy()
		{
			return null;
		}

		public byte type()
		{
			return 0;
		}

		public double dist2Collector()
		{
			return 0;
		}

		public String name()
		{
			return null;
		}

		public boolean isLine()
		{
			return false;
		}

		public boolean isPoint()
		{
			return false;
		}

		public boolean isCollectorItem()
		{
			return false;
		}

		public boolean isSteinerItem()
		{
			return false;
		}

		public boolean isWellItem()
		{
			return false;
		}

		public boolean isReadOnlyItem()
		{
			return false;
		}

		public boolean alreadyInSomeTree()
		{
			return false;
		}

		public double distanceFrom( ICommonItem pnt )
		{
			return 0;
		}

		public ICommonItem buildConnectItem( IPoint pnt )
		{
			return null;
		}
	}
}
